/**
 * LWG=> login with gateway
 * 会话通讯工具类，用于实现微服务向网关发起请求授权等操作
 * 1、微服务向网关注册服务，成功返回网关分配的token
 * 2、网关调用微服务接口，微服务验证网关合法性: 通过验证token和signature判断是否合法调用
 * 
 * @author lms 2022.08.08
 */
package ms.core.serv.system;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import lombok.Data;
import ms.core.common.ApiResult;
import ms.core.serv.tool.FeignTool;
import ms.core.tool.DateTimeTool;
import ms.core.tool.EncryptTool;
import ms.core.tool.JsonTool;
import ms.core.tool.Log4j2Tool;
import ms.core.tool.StrTool;
import ms.core.tool.SysTool;

public class LWGAuthorization implements Runnable{
	private Thread thread;
	private static boolean terminated;	// 用于结束服务标识

	private static String clientId;		// 网关分配的微服务id
	private static String secretKey;	// 网关分配的secretKey
	private static String serviceUrl;	// 微服务地址
	private static long tick = 0L;		// 记录最后一次运行时间
	
	public static String makeSignature(String clientId, String secretKey, long t) {
		String sign = EncryptTool.sha256(clientId+"~"+secretKey+"-"+t);
		return sign;
	}

	public synchronized static boolean checkAuth(long t, String signature) {
		if (t<=0 || StrTool.isBlank(signature))
			return false;

		return signature.equals(makeSignature(clientId, secretKey, t));
	}
	
	public static void start(String clientId, String secretKey, String serviceUrl) {
		LWGAuthorization auth = new LWGAuthorization(clientId, secretKey, serviceUrl);
		auth.start();
	}
	
	public synchronized static void stop() {
		terminated = true;
	}
	
	private synchronized static boolean isTerminated() {
		return terminated;
	}

	public LWGAuthorization(String cliId, String key, String svrUrl) { 
		clientId = cliId;
		secretKey = key;
		serviceUrl = svrUrl;
		terminated = false;
		thread = new Thread(this, clientId);
	}
	
	public void start() {
		thread.start();
	}

	private void online() {
		if (!Application.GATEWAY_REGISTER) return;
		
		try {
			long t = DateTimeTool.dateToUnixTime(new Date());

			Map<String, Object> body = new HashMap<>();
			body.put("clientId", clientId);
			body.put("serviceUrl", serviceUrl);
			body.put("t", t);
			body.put("sign", makeSignature(clientId, secretKey, t));
			ApiResult ret = FeignTool.callSys(Application.URL_GATEWAY, "lwgLogin", null, body);
			Log4j2Tool.info(LWGAuthorization.class, "微服务保持在线:"+ret.getMsg());
		} catch (Exception e) {
			Log4j2Tool.error(LWGAuthorization.class, "微服务保持在线", e);
		}
	}

	private void offline() {
		if (!Application.GATEWAY_REGISTER) return;

		try {
			long t = DateTimeTool.dateToUnixTime(new Date());

			Map<String, Object> body = new HashMap<>();
			body.put("clientId", clientId);
			body.put("serviceUrl", serviceUrl);
			body.put("t", t);
			body.put("sign", makeSignature(clientId, secretKey, t));
			ApiResult ret = FeignTool.callSys(Application.URL_GATEWAY, "lwgLogout", null, body);
			Log4j2Tool.info(LWGAuthorization.class, "微服务下线:"+ret.getMsg());
		} catch (Exception e) {
			Log4j2Tool.error(LWGAuthorization.class, "微服务注销", e);
		}
	}

	@Override
	public void run() {	
		while (!isTerminated()) {
			long now = (new Date()).getTime();
			// n秒一次握手
			if (now-tick>=Application.KEEP_ALIVE * 1000) {
				tick = now;
				online();
			}
			SysTool.sleep(100);
		}
		offline();
		Application.stop();
	}

    @Data
    public static class LWGAuth {
    	// 微服务与网关鉴权信息
    	private String clientId;	// 微服务Id
    	private long t;				// 时间戳
    	private String sign;		// 签名 = sha256(clientId+"")
    	// 当前登录帐户信息
    	private String userUid;
    	private String account;
    	private String corpUid;
    	private int ctype;
    	private int root; 			// 0-子账号;1-主账号
    	
    	public String toString() {
    		return JsonTool.objectToJson(this);
    	}    	
    }	
}
